package readini

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"runtime"
	"strings"
	"unicode"
)

const (
	// DefaultSection 是默认 section 的名称.
	// 在大多数情况下，访问该 section 只需使用空字符串"".
	DefaultSection = "DEFAULT"

	// KeyValueDelimiter 是用于分隔 key 和 value 的分隔符.
	KeyValueDelimiter = "="
)

var (
	// CommentSymbol 表明注释开始.
	// 在 Windows 系统中, 初始化时该变量会自动变为";".
	CommentSymbol = "#"

	// LineBreak 表明新行开始.
	// 在 Windows 系统中, 初始化时该变量会自动变为"\r\n".
	LineBreak = "\n"
)

func init() {
	switch runtime.GOOS {
	case "windows":
		CommentSymbol = ";"
		LineBreak = "\r\n"
	case "linux":
		CommentSymbol = "#"
		LineBreak = "\n"
	}
}

func parse(cfg *Configuration, reader *bufio.Reader) error {

	isEOF := false
	secName := DefaultSection
	for !isEOF {
		line, err := getLine(reader, &isEOF)
		if err != nil {
			return err
		}
		if len(line) == 0 {
			continue
		}
		// Comments
		if line[0] == CommentSymbol[0] {
			continue
		}
		// Section
		if line[0] == '[' {
			secName, err = parseSecName(line, cfg)
			if err != nil {
				return err
			}
			continue
		}
		// DefaultSection
		if len(cfg.SectionList) == 0 {
			err = cfg.newSection(secName)
			if err != nil {
				return err
			}
		}
		// Keyname
		keyName, offset, err := parseKeyName(string(line))
		if err != nil {
			return err
		}
		// Value
		value, err := parseValue(string(line[offset:]))
		if err != nil {
			return err
		}
		// create Key-Value
		err = cfg.Sections[secName].newKeyVal(keyName, value)
		if err != nil {
			return err
		}
	}
	return nil
}

func getLine(buffer *bufio.Reader, isEOF *bool) ([]byte, error) {
	line, err := buffer.ReadBytes('\n')
	if err == io.EOF {
		*isEOF = true
		err = nil
	} else if err != nil {
		return nil, err
	}
	line = bytes.TrimLeftFunc(line, unicode.IsSpace)
	return line, err

}

func parseSecName(line []byte, cfg *Configuration) (string, error) {
	closeIdx := bytes.LastIndexByte(line, ']')
	if closeIdx == -1 {
		return "", fmt.Errorf("Unclosed section: %s", line)
	}
	secName := string(line[1:closeIdx])
	err := cfg.newSection(secName)
	if err != nil {
		return "", err
	}
	return secName, nil
}

func parseKeyName(line string) (string, int, error) {
	endIdx := strings.IndexAny(line, KeyValueDelimiter)
	if endIdx < 0 {
		return "", -1, fmt.Errorf("Delimiter(%s) not found", KeyValueDelimiter)
	}
	return strings.TrimSpace(line[0:endIdx]), endIdx + 1, nil
}

func parseValue(line string) (string, error) {
	line = strings.TrimSpace(line)
	if len(line) == 0 {
		return "", nil
	}

	i := strings.IndexAny(line, "#;")
	if i > -1 {
		line = strings.TrimSpace(line[:i])
	}
	return line, nil
}
